#include "interprete.h"
#include "entrenador.h"

Interprete::Interprete()
{
	numeroNotaActual = 0;
	numeroCompasActual = 0;
}

Interprete::~Interprete()
{

}

void Interprete::setPatron(const Patron& patron)
{
	this->patron = patron;
    // TODO: ver que pasa con tiempos en amalgama
    Compas compas = patron.getCompas(0);

    metronomo.setPulsosPorCompas(compas.getNumeroPulsos());
}


//void Interprete::setCompas(const Compas& compas)
//{
//	   // TODO: hacer que se puedan ejecutar varios compases
//	this->compas = compas;
//    metronomo.setPulsosPorCompas(compas.getNumeroPulsos());
//}

void Interprete::inicio()
{	
	primeraNota();
	//procesarNota();
	metronomo.arrancar();
}

void Interprete::proceso()
{	
	metronomo.comprobarSonido();

	if (!notaActual.esValida()) {
		siguienteNota();
		return;
	}

	while (procesarNota()) {
		siguienteNota();
	}
}

void Interprete::fin()
{
	metronomo.parar();
}

quint64 Interprete::getMilisegundoInicioPatron()
{        
    int numeroCompasesPorPatron = patron.getNumeroCompases();
    if (numeroCompasesPorPatron == 0) {
        return 0;
    }

    int numeroPatron = metronomo.getNumeroCompasActual() / numeroCompasesPorPatron;
    //int numeroCompasRelativoAlPatron = metronomo.getNumeroCompasActual() % numeroCompasesPorPatron;

    //qint64 milisegundoInicioCompas = metronomo.getMilisegundoInicioCompas();

    return numeroPatron * numeroCompasesPorPatron * metronomo.getMilisegundosPorCompas();// + milisegundoInicioCompas; 
}

#define MARGEN_ERROR_MS 2

bool Interprete::procesarNota()
{
    quint64 msActual = metronomo.getMilisegundosDesdeInicio();

	double milisegundosPorCompas = metronomo.getMilisegundosPorCompas();
	double milisegundosPorPulso = metronomo.getMilisegundosPorPulso();
	double milisegundosPorDivision = milisegundosPorPulso / notaActual.getDivisiones();

	quint64 msNotaActual =
		numeroCompasActual * milisegundosPorCompas +
		notaActual.getPulso() * milisegundosPorPulso +
		notaActual.getDivision() * milisegundosPorDivision;

	qint64 diferenciaMilisegundos;
	if (msNotaActual >= msActual) {
		diferenciaMilisegundos = msNotaActual - msActual;
	} else {
		diferenciaMilisegundos = - (double) (msActual - msNotaActual);
	}

	if (diferenciaMilisegundos > MARGEN_ERROR_MS) {
		// aun no le toca
		return false;
	}
	if (diferenciaMilisegundos < -MARGEN_ERROR_MS) {
		// se ha pasado su momento
		return true;
	}

	QString nombreNota = notaActual.getNombreNota();
	Entrenador::getInstancia()->marcarNotaEntrenamiento(msNotaActual, nombreNota);	
	return true;
}

Compas Interprete::getCompasActual()
{
    return compasActual;
}

double Interprete::getProporcionCompletadaDelPatron() 
{    
    int numeroCompases = patron.getNumeroCompases();
    if (numeroCompases == 0) {
        return 0;
    }
    double proporcionCompletadoCompas = metronomo.getProporcionCompletadoCompas();
    int numeroCompasRelativoAlPatron = metronomo.getNumeroCompasActual() % numeroCompases;
    return (numeroCompasRelativoAlPatron + proporcionCompletadoCompas) / numeroCompases;
}

void Interprete::primeraNota()
{
    numeroCompasActual = 0;
    compasActual = patron.getNumeroCompases() > 0 ? patron.getCompas(0) : Compas(); 

	if (compasActual.getNumeroNotas() == 0) {
		return;
	}
	
	numeroNotaActual = 0;
	notaActual = compasActual.getNota(0);
}

void Interprete::siguienteNota()
{    
    if (patron.getNumeroCompases() == 0) {
        return;
    }

    int numeroCompasMetronomo = metronomo.getNumeroCompasActual();

    if (numeroCompasActual < numeroCompasMetronomo) {
        asignarCompasActual(numeroCompasMetronomo);
    } else if (numeroCompasActual == numeroCompasMetronomo) {
    	int numeroNotas = compasActual.getNumeroNotas();
        if (numeroNotas == 0 || numeroNotaActual >= numeroNotas) {
            asignarCompasActual(numeroCompasMetronomo + 1);
        }
    } else {
        return;
    }

	notaActual = compasActual.getNota(numeroNotaActual++);
}

void Interprete::asignarCompasActual(int numeroCompas)
{
    qDebug() << "Compas actual: " << numeroCompas;
    numeroCompasActual = numeroCompas;
    compasActual = patron.getCompas(numeroCompasActual);
    numeroNotaActual = 0;
}
